#include "cafun.h"

#define DATAPACKAGESIZE 96
#define DATASIZE 68

uint8_t identify_flag;
uint8_t refuse_cnt;
uint8_t hasheadnode;
node_data head_node;

uint8_t apply_key_flag;

uint8_t Ca_Self_ID[8];
uint8_t Ca_Self_Sig_Pk[SIG_PK_LEN];
uint8_t Ca_Sig_Msg[KEM_PK_LEN + SIGNATURE_LEN];
uint8_t Ca_Sig_Res[VALID_LEN];
uint8_t Auth_Res[2 + SIGNATURE_LEN];

void time_to_rid(uint8_t *RIDA, struct tm *timeinfo)
{
	int year_end = timeinfo->tm_year + 1900, month_end = timeinfo->tm_mon + 1, day_end = timeinfo->tm_mday;
	int a = year_end / 100, b = year_end - a * 100;
	RIDA[0] = (uint8_t)a, RIDA[1] = (uint8_t)b;
	RIDA[2] = (uint8_t)month_end, RIDA[3] = (uint8_t)day_end;
	for (int i = 4; i < 8; i++)
	{
		RIDA[i] = (uint8_t)rand() % 255;
	}
}

void time_to_ptm(struct tm *timeinfo, past_tm *pt)
{
	int year_end = timeinfo->tm_year + 1900;
	int month_end = timeinfo->tm_mon + 1;
	int day_end = timeinfo->tm_mday;
	pt->year = year_end;
	pt->month = month_end;
	pt->day = day_end;
}

void params_init(ca_oppo *oparams, ca_self *sparams, char *IDA, char *IPA)
{
	time_t raw_time = time(NULL);
	struct tm *timeinfo;
	timeinfo = localtime(&raw_time);
	memmove(sparams->selfid, IDA, 8);
	memmove(sparams->selfip, IPA, 26);
	uint8_t datapackage[96] = {0};
	uint8_t con_f[4] = {0};
	memmove(sparams->datapackage, datapackage, 96);
	memmove(sparams->con_flag, con_f, 4);
	sparams->data = NULL;
	// printf("init_successful!\n");
}

// context_hmac(TA2)
TEEC_Result Context_Hmac(TEEC_Context ctx, TEEC_Session sess, char *oppoid, char *data, uint8_t *datapackage, uint8_t *sk_flag)
{
	TEEC_Result res1;
	TEEC_Operation op;
	uint32_t origin;
	uint8_t output[96] = {0};
	memset(&op, 0, sizeof(op));
	op.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_TEMP_INPUT,
									 TEEC_MEMREF_TEMP_OUTPUT,
									 TEEC_MEMREF_TEMP_INPUT,
									 TEEC_MEMREF_TEMP_INPUT);
	size_t data_len = strlen(data);
	// uint8_t enpkey[112] ={0} ;
	op.params[0].tmpref.buffer = data;
	op.params[0].tmpref.size = data_len;
	op.params[1].tmpref.buffer = output;
	op.params[1].tmpref.size = 96;
	op.params[2].tmpref.buffer = oppoid;
	op.params[2].tmpref.size = 8;
	op.params[3].tmpref.buffer = sk_flag;
	op.params[3].tmpref.size = 1;
	res1 = TEEC_InvokeCommand(&sess,
							  TA2_CONTEXT_HMAC,
							  &op, &origin);
	// printf("output:\n");
	// format_print(output, 96);
	memmove(datapackage, output, 96);
	return res1;
}

TEEC_Result Context_DeHmac(TEEC_Context ctx, TEEC_Session sess, char *oppoid, uint8_t *datapackage, char *data, uint8_t *sk_flag)
{
	TEEC_Result res1;
	TEEC_Operation op;
	uint32_t origin;
	uint8_t dedata[72] = {0};
	dedata[0] = 0x00;
	dedata[1] = 0x00;
	memset(&op, 0, sizeof(op));
	op.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_TEMP_INPUT,
									 TEEC_MEMREF_TEMP_OUTPUT,
									 TEEC_MEMREF_TEMP_INPUT,
									 TEEC_MEMREF_TEMP_INPUT);
	op.params[0].tmpref.buffer = datapackage;
	op.params[0].tmpref.size = DATAPACKAGESIZE;
	op.params[1].tmpref.buffer = dedata;
	op.params[1].tmpref.size = 72;
	op.params[2].tmpref.buffer = oppoid;
	op.params[2].tmpref.size = 8;
	op.params[3].tmpref.buffer = sk_flag;
	op.params[3].tmpref.size = 1;
	res1 = TEEC_InvokeCommand(&sess,
							  TA2_CONTEXT_DEHMAC,
							  &op, &origin);
	// printf("\nDeHmac res1=%d\n",res1);
	memmove(data, dedata, 72);
}
// 无论返回怎样结果都需要进行更新（需要回收msg结构体，pwd=1代表更新 pwd=0代表不更新）
TEEC_Result Context_Update(TEEC_Context ctx, TEEC_Session sess, uint8_t pwd)
{
	TEEC_Result res1;
	TEEC_Operation op;
	uint32_t origin;
	memset(&op, 0, sizeof(op));
	op.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_TEMP_INPUT,
									 TEEC_NONE,
									 TEEC_NONE,
									 TEEC_NONE);
	uint8_t pos[] = {0x00, 0x00, 0x00, 0x00};
	if (pwd)
	{
		pos[0] = 0x01;
	}
	op.params[0].tmpref.buffer = pos;
	op.params[0].tmpref.size = 4;
	// printf("\nupdate_test1\n");
	res1 = TEEC_InvokeCommand(&sess,
							  TA2_CONTEXT_UPDATE,
							  &op, &origin);

	// printf("\nupdate_test2\n");
}

void format_print(uint8_t *arg, size_t len)
{
	size_t k = len / 8;
	for (int i = 0; i < k; i++)
	{
		for (int j = 0; j < 8; j++)
		{
			printf("%02X  ", arg[j + i * 8]);
		}
		printf("\n");
	}
}

void node_data_init(node_data *head, uint8_t *id, char *ip)
{
	// printf("\nnode_init!\n");
	head->next = NULL;
	head->new_sk_flag = 1;
	memmove(head->nodeID, id, 8);
	memmove(head->nodeIP, ip, 26);
}

int Str_Equal(char *b1, char *b2, int len)
{
	int i = 0;
	while (i < len)
	{
		if (b1[i] != b2[i])
			return 0;
		i++;
	}
	return 1;
}

void node_data_add(node_data *head, uint8_t *id, char *ip)
{
	// printf("\nnode_add!\n");
	node_data *node = head;
	node_data *prev = NULL;
	while (node != NULL)
	{
		if (Str_Equal(node->nodeIP, ip, 26))
		{
			node->new_sk_flag = 1;
			break;
		}
		prev = node;
		node = node->next;
	}
	if (node == NULL)
	{
		node = (node_data *)malloc(sizeof(node_data));
		memmove(node->nodeID, id, 8);
		memmove(node->nodeIP, ip, 26);
		node->next = NULL;
		node->new_sk_flag = 1;
		prev->next = node;
	}
}

// 1.found  0.not_found
int node_data_search(node_data *head, char *ip, uint8_t *out_id, uint8_t *sk_flag)
{
	node_data *node = head;
	node_data *prev = NULL;
	while (node != NULL)
	{
		if (Str_Equal(node->nodeIP, ip, 26))
		{
			memmove(out_id, node->nodeID, 8);
			*sk_flag = node->new_sk_flag;
			return 1;
		}
		prev = node;
		node = node->next;
	}
	if (node == NULL)
	{
		printf("\nNot_found!\n");
		return 0;
	}
}

void node_data_update_skflag(node_data *head, char *ip)
{
	node_data *node = head;
	node_data *prev = NULL;
	while (node != NULL)
	{
		if (Str_Equal(node->nodeIP, ip, 26))
		{
			node->new_sk_flag = 0;
			return 1;
		}
		prev = node;
		node = node->next;
	}
	return 1;
}

TEEC_Result Sk_Secure_Read(TEEC_Context ctx, TEEC_Session sess, char *oppoid)
{
	TEEC_Result res1;
	TEEC_Operation op;
	uint32_t origin;
	memset(&op, 0, sizeof(op));
	op.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_TEMP_INPUT,
									 TEEC_NONE,
									 TEEC_NONE,
									 TEEC_NONE);
	op.params[0].tmpref.buffer = oppoid;
	op.params[0].tmpref.size = 8;
	res1 = TEEC_InvokeCommand(&sess,
							  TA2_SECURE_READ,
							  &op, &origin);
	return res1;
}

TEEC_Result save_opposigpk_invoke(TEEC_Context ctx, TEEC_Session sess, uint8_t *oppo_id, uint8_t *oppo_sig_pk)
{
	// printf("\nSave opposigpk invoke\n");
	TEEC_Result res1;
	TEEC_Operation op;
	uint32_t origin;
	struct timeval start, end;
	memset(&op, 0, sizeof(op));
	op.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_TEMP_INPUT,
									 TEEC_MEMREF_TEMP_INPUT,
									 TEEC_NONE,
									 TEEC_NONE);
	op.params[0].tmpref.buffer = oppo_id;
	op.params[0].tmpref.size = 8;
	op.params[1].tmpref.buffer = oppo_sig_pk;
	op.params[1].tmpref.size = SIG_PK_LEN;
	// gettimeofday(&start, NULL);
	res1 = TEEC_InvokeCommand(&sess,
							  TA_SAVE_OPPOSIGPK,
							  &op, &origin);
	// printf("\nexchangeR successful!\n");
	// gettimeofday(&end, NULL);
	// long timeuse = 1000000 * (end.tv_sec - start.tv_sec) + end.tv_usec - start.tv_usec;
	// printf("\nSave opposigpk time=%fs\n", timeuse / 1000000.0);
	// printf("\nSave opposigpk successful!\n");
	return res1;
}

TEEC_Result sig_keypair_invoke(TEEC_Context ctx, TEEC_Session sess, uint8_t *self_sig_pk)
{
	printf("**************************************************************\n");
	printf("Start \033[1;34m\"Generate Signature Key Pairs\"\033[0m\n");
	TEEC_Result res1;
	TEEC_Operation op;
	uint32_t origin;
	struct timeval start, end;
	memset(&op, 0, sizeof(op));
	op.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_TEMP_OUTPUT,
									 TEEC_NONE,
									 TEEC_NONE,
									 TEEC_NONE);
	op.params[0].tmpref.buffer = self_sig_pk;
	op.params[0].tmpref.size = SIG_PK_LEN;
	gettimeofday(&start, NULL);
	res1 = TEEC_InvokeCommand(&sess,
							  TA_SIG_KEYPAIR,
							  &op, &origin);
	gettimeofday(&end, NULL);
	long timeuse = 1000000 * (end.tv_sec - start.tv_sec) + end.tv_usec - start.tv_usec;
	printf("Generate Signature Key Pairs Time=%.3fms\n", timeuse / 1000.0);
	printf("\033[1;34m\"Generate Signature Key Pairs\"\033[0m is \033[1;32mAccomplished\033[0m!\n");
	printf("**************************************************************\n");
	return res1;
}

TEEC_Result kem_keypair_invoke(TEEC_Context ctx, TEEC_Session sess, uint8_t *sig_msg)
{
	printf("\n1. Start \033[1;34m\"Generate KEM Key Pairs\"\033[0m\n");
	TEEC_Result res1;
	TEEC_Operation op;
	uint32_t origin;
	struct timeval start, end;
	memset(&op, 0, sizeof(op));
	op.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_TEMP_OUTPUT,
									 TEEC_NONE,
									 TEEC_NONE,
									 TEEC_NONE);
	op.params[0].tmpref.buffer = sig_msg;
	op.params[0].tmpref.size = KEM_PK_LEN + SIGNATURE_LEN;
	gettimeofday(&start, NULL);
	res1 = TEEC_InvokeCommand(&sess,
							  TA_KEM_KEYPAIR,
							  &op, &origin);
	gettimeofday(&end, NULL);
	long timeuse = 1000000 * (end.tv_sec - start.tv_sec) + end.tv_usec - start.tv_usec;
	printf("1. Generate KEM Key Pairs Time=%.3fms\n", timeuse / 1000.0);
	printf("1. \033[1;34m\"Generate KEM Key Pairs\"\033[0m is \033[1;32mAccomplished\033[0m!\n");
	return res1;
}

TEEC_Result authen_encape_invoke(TEEC_Context ctx, TEEC_Session sess, uint8_t *oppo_id, uint8_t *sig_msg, uint8_t *sig_ct)
{
	// printf("\nAuth encape invoke\n");
	printf("\n2. Start \033[1;34m\"Encapsulate Authentication Data\"\033[0m\n");
	TEEC_Result res1;
	TEEC_Operation op;
	uint32_t origin;
	struct timeval start, end;
	memset(&op, 0, sizeof(op));
	op.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_TEMP_INPUT,
									 TEEC_MEMREF_TEMP_INPUT,
									 TEEC_MEMREF_TEMP_OUTPUT,
									 TEEC_NONE);
	op.params[0].tmpref.buffer = sig_msg;
	op.params[0].tmpref.size = KEM_PK_LEN + SIGNATURE_LEN;
	op.params[1].tmpref.buffer = oppo_id;
	op.params[1].tmpref.size = 8;
	op.params[2].tmpref.buffer = sig_ct;
	op.params[2].tmpref.size = CT_LEN + SIGNATURE_LEN;
	gettimeofday(&start, NULL);
	res1 = TEEC_InvokeCommand(&sess,
							  TA_AUTHEN_ENCAPE,
							  &op, &origin);
	gettimeofday(&end, NULL);
	long timeuse = 1000000 * (end.tv_sec - start.tv_sec) + end.tv_usec - start.tv_usec;
	printf("2. Encapsulate Authentication Data Time=%.3fms\n", timeuse / 1000.0);
	printf("2. \033[1;34m\"Encapsulate Authentication Data\"\033[0m is \033[1;32mAccomplished\033[0m!\n");
	return res1;
}

TEEC_Result authen_decape_invoke(TEEC_Context ctx, TEEC_Session sess, uint8_t *oppo_id, uint8_t *sig_ct, uint8_t *auth_res)
{
	// printf("\nAuth decape invoke\n");
	printf("\n3. Start \033[1;34m\"Decapsulate Authentication Data\"\033[0m\n");
	TEEC_Result res1;
	TEEC_Operation op;
	uint32_t origin;
	struct timeval start, end;
	memset(&op, 0, sizeof(op));
	op.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_TEMP_INPUT,
									 TEEC_MEMREF_TEMP_INPUT,
									 TEEC_MEMREF_TEMP_OUTPUT,
									 TEEC_NONE);
	op.params[0].tmpref.buffer = sig_ct;
	op.params[0].tmpref.size = CT_LEN + SIGNATURE_LEN;
	op.params[1].tmpref.buffer = oppo_id;
	op.params[1].tmpref.size = 8;
	op.params[2].tmpref.buffer = auth_res;
	op.params[2].tmpref.size = 2;
	gettimeofday(&start, NULL);
	res1 = TEEC_InvokeCommand(&sess,
							  TA_AUTHEN_DECAPE,
							  &op, &origin);
	gettimeofday(&end, NULL);
	// printf("\n Auth_RES = %c\n", auth_res[0]);
	long timeuse = 1000000 * (end.tv_sec - start.tv_sec) + end.tv_usec - start.tv_usec;
	printf("3. Decapsulate Authentication Data Time=%.3fms\n", timeuse / 1000.0);
	printf("3. \033[1;34m\"Decapsulate Authentication Data\"\033[0m is \033[1;32mAccomplished\033[0m!\n");
	return res1;
}

TEEC_Result ta_sign_invoke(TEEC_Context ctx, TEEC_Session sess, uint8_t *oppo_id, uint8_t *sig_msg, uint8_t *sig_ct, size_t *sig_ct_len)
{
	// printf("\nTA sign invoke\n");
	// printf("\n4. Start \033[1;34m\"Signature Key Verification Data\"\033[0m\n");
	TEEC_Result res1;
	TEEC_Operation op;
	uint32_t origin;
	// struct timeval start, end;
	memset(&op, 0, sizeof(op));
	op.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_TEMP_INPUT,
									 TEEC_MEMREF_TEMP_INPUT,
									 TEEC_MEMREF_TEMP_OUTPUT,
									 TEEC_MEMREF_TEMP_OUTPUT);
	op.params[0].tmpref.buffer = sig_msg;
	op.params[0].tmpref.size = 2;
	op.params[1].tmpref.buffer = oppo_id;
	op.params[1].tmpref.size = 8;
	op.params[2].tmpref.buffer = sig_ct;
	op.params[2].tmpref.size = 2 + SIGNATURE_LEN;
	op.params[3].tmpref.buffer = sig_ct_len;
	op.params[3].tmpref.size = sizeof(size_t);
	// gettimeofday(&start, NULL);
	res1 = TEEC_InvokeCommand(&sess,
							  TA_SIGN,
							  &op, &origin);
	// gettimeofday(&end, NULL);
	// long timeuse = 1000000 * (end.tv_sec - start.tv_sec) + end.tv_usec - start.tv_usec;
	// printf("\nTA sign time=%fs\n", timeuse / 1000000.0);
	// printf("\nTA sign successful!\n");
	// printf("4. Signature Key Verification Data Time=%.3fms\n", timeuse / 1000.0);
	// printf("4. \033[1;34m\"Signature Key Verification Data\"\033[0m is \033[1;32mAccomplished\033[0m!\n");
	// format_print(sig_ct,CT_LEN + SIGNATURE_LEN);
	return res1;
}

TEEC_Result ta_sign_verify_invoke(TEEC_Context ctx, TEEC_Session sess, uint8_t *oppo_id, uint8_t *sig_ct, uint8_t *result, size_t *auth_res_len)
{
	// printf("\nSign verify invoke\n");
	printf("\n5. Start \033[1;34m\"Verify Key Verification Data\"\033[0m\n");
	TEEC_Result res1;
	TEEC_Operation op;
	uint32_t origin;
	struct timeval start, end;
	memset(&op, 0, sizeof(op));
	op.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_TEMP_INPUT,
									 TEEC_MEMREF_TEMP_INPUT,
									 TEEC_MEMREF_TEMP_OUTPUT,
									 TEEC_MEMREF_TEMP_OUTPUT);
	op.params[0].tmpref.buffer = sig_ct;
	op.params[0].tmpref.size = 2 + SIGNATURE_LEN;
	op.params[1].tmpref.buffer = oppo_id;
	op.params[1].tmpref.size = 8;
	op.params[2].tmpref.buffer = result;
	op.params[2].tmpref.size = 2;
	op.params[3].tmpref.buffer = auth_res_len;
	op.params[3].tmpref.size = sizeof(size_t);
	gettimeofday(&start, NULL);

	// printf("\nresult = %c\n", result[0]);
	res1 = TEEC_InvokeCommand(&sess,
							  TA_SIGN_VERIFY,
							  &op, &origin);
	// printf("3 res1=%d\n",res1);
	// printf("\n3 result = %c\n", result[0]);
	// printf("\n3 auth_res_len = %c\n", auth_res_len);
	// printf("\n3 auth_res_len d= %d\n", auth_res_len);
	// format_print(auth_res_len, sizeof(size_t));
	gettimeofday(&end, NULL);
	long timeuse = 1000000 * (end.tv_sec - start.tv_sec) + end.tv_usec - start.tv_usec;
	// printf("\nSign verify time=%fs\n", timeuse / 1000000.0);
	// printf("\nSign verify successful!\n");
	printf("5. Verify Key Verification Data Time=%.3fms\n", timeuse / 1000.0);
	return res1;
}

TEEC_Result ta_sign_verify_context_invoke(TEEC_Context ctx, TEEC_Session sess, uint8_t *oppo_id, uint8_t *sig_ct, uint8_t *auth_res, size_t *auth_res_len)
{
	// printf("\nSign verify Context invoke\n");
	printf("\nStart \033[1;34m\"Verify Content Authentication Result\"\033[0m\n");
	TEEC_Result res6;
	TEEC_Operation op;
	uint32_t origin;
	struct timeval start, end;
	memset(&op, 0, sizeof(op));
	op.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_TEMP_INPUT,
									 TEEC_MEMREF_TEMP_INPUT,
									 TEEC_MEMREF_TEMP_OUTPUT,
									 TEEC_MEMREF_TEMP_OUTPUT);
	op.params[0].tmpref.buffer = sig_ct;
	op.params[0].tmpref.size = 2 + SIGNATURE_LEN;
	op.params[1].tmpref.buffer = oppo_id;
	op.params[1].tmpref.size = 8;
	op.params[2].tmpref.buffer = auth_res;
	op.params[2].tmpref.size = 2;
	op.params[3].tmpref.buffer = auth_res_len;
	op.params[3].tmpref.size = sizeof(size_t);
	gettimeofday(&start, NULL);

	res6 = TEEC_InvokeCommand(&sess,
							  TA_CONTEXT_SIGN_VERIFY,
							  &op, &origin);

	gettimeofday(&end, NULL);
	long timeuse = 1000000 * (end.tv_sec - start.tv_sec) + end.tv_usec - start.tv_usec;
	// printf("\nSign verify Context time=%.3fms\n", timeuse / 1000.0);
	// printf("\nSign verify Context successful!\n");
	printf("Verify Content Authentication Result Time=%.3fms\n", timeuse / 1000.0);
	printf("\033[1;34m\"Verify Content Authentication Result\"\033[0m is \033[1;32mAccomplished\033[0m!\n");
	return res6;
}

void generate_string(char *dest, int len)
{

	char metachar[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
	srand(time(NULL) + rand());
	for (int i = 0; i < len - 1; i++)
	{
		dest[i] = metachar[rand() % 62];
	}
	dest[len - 1] = '\0';
}

void get_local_IP(char *destIP)
{
	int sockfd;
	struct ifconf ifc;
	char buf[1024] = {0};
	char ipbuf[20] = {0};
	int iplen = 0;
	struct ifreq *ifr;

	ifc.ifc_len = 1024;
	ifc.ifc_buf = buf;

	if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
	{
		printf("socket error\n");
		return -1;
	}
	ioctl(sockfd, SIOCGIFCONF, &ifc);
	ifr = (struct ifreq *)buf;

	for (int i = (ifc.ifc_len / sizeof(struct ifreq)); i > 0; i--)
	{
		// printf("net name: %s\n",ifr->ifr_name);
		if (Str_Equal(ifr->ifr_name, "eth0", 4))
		{
			inet_ntop(AF_INET, &((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr, ipbuf, 20);
			iplen = strlen(ipbuf);
			memmove(destIP, "tcp://", 6);
			memmove(destIP + 6, ipbuf, iplen);
			memmove(destIP + 6 + iplen, ":5566", 5);
			// printf("ip: %s \n",ipbuf);
		}
		ifr = ifr + 1;
	}
}

int checkIP(const char *p)
{
	int ip_part_1;
	int ip_part_2;
	int ip_part_3;
	int ip_part_4;
	char end_part;
	if (sscanf(p, "%d.%d.%d.%d%c",
			   &ip_part_1, &ip_part_2, &ip_part_3, &ip_part_4, &end_part) == 4)
	{
		if (
			(ip_part_1 >= 0 && ip_part_1 <= 255) &&
			(ip_part_2 >= 0 && ip_part_2 <= 255) &&
			(ip_part_3 >= 0 && ip_part_3 <= 255) &&
			(ip_part_4 >= 0 && ip_part_4 <= 255))
			return 1;
		else
			return 0;
	}
	else
		return 0;
}